/*
###################################################################
#                       LINDO-API
#                    Sample Programs
#                  Copyright (c) 2001-2002
#
#         LINDO Systems, Inc.           312.988.7422
#         1415 North Dayton St.         info@lindo.com
#         Chicago, IL 60622             http://www.lindo.com
###################################################################

  @file   : ex_user.c

  @purpose: Solve an NLP that uses a user-defined function @f(a,b) 
  to compute the objective function value. 
  
             minimize x * @f( sin(pi*x), cos(pi*x))
                                                               
             0 <= x <= 10
    
  @remark : This application uses the Instruction Style Interface. 
  The Instruction list is input from an MPI-file (ex_user.mpi). 
  
  @remark : EP_USER operator is used in the instruction list to 
  specify the number of arguments @f() takes.

  @remark : LSsetUsercalc() function is used to set the user-defined
  MyFunc() function as @f. 

*/


#include 
#include 
#include 
/* LINDO API header file */
#include "lindo.h"
/* license.h must be edited to include the license key 
    that came with your software */
#include "license.h"
/* Define a macro to declare variables for                   
    error checking */
#define APIERRORSETUP  \
   int nErrorCode; \
   char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
                        
/* Define a macro to do our error checking */
#define APIERRORCHECK  \
   if (nErrorCode) \
   { \
      if ( pEnv) \
      { \
         LSgetErrorMessage( pEnv, nErrorCode, \
          cErrorMessage); \
         printf("nErrorCode=%d:  %s\n", nErrorCode, \
          cErrorMessage); \
      } else {\
         printf( "Fatal Error\n"); \
      } \
      exit(1); \
   } \

/********************************************************
* Set up an output log function. 
*/
static void CALLTYPE print_line(pLSmodel model, 
                                char *line, void *notting)
{
 if (line)
 {
   printf("%s",line);
 } /*if*/
} /*print_line*/



/****************************************
* Implement the user function @f(). 
*/
int CALLTYPE MyFunc( pLSmodel model,
                     int      nargs,
                     double   *argval,
                     void     *UserData,
                     double   *FuncVal)
{
   int i;
   double f = 0.0;
   double a = argval[0];
   double b = argval[1];

   f = sin(a) + sin(b);

   *FuncVal = f;

   return (0);
} /*print_line*/


/*************************************
* main entry point 
*/
int main()

{
 APIERRORSETUP;
 pLSenv pEnv;
 pLSmodel pModel;

 /* 
 * >>> Step 1 <<< Create a LINDO environment. 
 */
 pEnv = LScreateEnv ( &nErrorCode, MY_LICENSE_KEY);
 if ( nErrorCode == LSERR_NO_VALID_LICENSE)
 {
   printf( "Invalid License Key!\n");
   exit( 1);
 }
 APIERRORCHECK;

 /* 
 * >>> Step 2 <<< Create a model in the environment. 
 */
 pModel = LScreateModel(pEnv,&nErrorCode);
 APIERRORCHECK;


 /* 
 * >>>> Step 3 <<< Set up the instruction list of the model. 
 */
 {
   int nLinearz, nAutoDeriv, nConvexRelax, nCRAlgReform;

   /*  Set a log function to call.  */
   nErrorCode = LSsetLogfunc(pModel,(printLOG_t) print_line,NULL);
   APIERRORCHECK;

   /* Set linearization level, before a call to LSloadNLPCode.
   * If not specified, the solver will decide */
   nLinearz = 1;
   nErrorCode = LSsetModelIntParameter (pModel,  
     LS_IPARAM_NLP_LINEARZ, nLinearz);
   APIERRORCHECK;

   /* Select algebraic reformulation level in convex relaxation*/
   nCRAlgReform = 1;
   nErrorCode = LSsetModelIntParameter (pModel,  
     LS_IPARAM_NLP_CR_ALG_REFORM, nCRAlgReform);
   APIERRORCHECK;

   /* Select convex relax level */
   nConvexRelax = 0;
   nErrorCode = LSsetModelIntParameter (pModel,  
     LS_IPARAM_NLP_CONVEXRELAX, nConvexRelax);
   APIERRORCHECK;

   /* 
   * Set up automatic differentiation, before a call to LSreadMPIFile. 
   * If not specified, the numerical derivative will be applied 
   */
   nAutoDeriv = 0;
   nErrorCode = LSsetModelIntParameter (pModel, 
     LS_IPARAM_NLP_AUTODERIV, nAutoDeriv);
   APIERRORCHECK;

   /* Set up MyFunc() as the user functionas */ 
   nErrorCode = LSsetUsercalc (pModel, 
     (user_callback_t) MyFunc, NULL);
   APIERRORCHECK;

   /* Read instructions from an MPI-file */
   nErrorCode = LSreadMPIFile (pModel,"ex_user.mpi");
   APIERRORCHECK;
 }


 /* 
 * >>> Step 5 <<< Perform the optimization using the
 *                multi-start solver
 */

 /* set multi-start as the current NLP solver */
 nErrorCode = LSsetModelIntParameter (pModel, 
     LS_IPARAM_NLP_SOLVER, LS_NMETHOD_MSW_GRG);
   APIERRORCHECK;

 nErrorCode = LSoptimize(pModel, LS_METHOD_FREE, NULL);
 APIERRORCHECK;


 /* 
 * >>> Step 6 <<< Retrieve the solution 
 */
 {
   int nLinearity, i, stat, nvars, ncons;
   double objval=0.0, primal[1000];

   /* Get the linearity of the solved model */
   nErrorCode = LSgetModelIntParameter (pModel,  
     LS_IPARAM_NLP_LINEARITY, &nLinearity);
   APIERRORCHECK;

   nErrorCode = LSgetModelParameter(pModel,LS_IPARAM_STATUS,&stat);
   APIERRORCHECK;
   printf("\n\n\nSolution status = %d \n",stat);

   /* Report the status of solution */
   nErrorCode = LSgetInfo(pModel, LS_IINFO_NUM_VARS,&nvars);     
   APIERRORCHECK;  

   nErrorCode = LSgetInfo(pModel, LS_IINFO_NUM_CONS,&ncons);     
   APIERRORCHECK;  

   if (nLinearity)
   {
     printf("\nModel has been completely linearized.\n");
   }
   else
   {
     printf("\nModel is nonlinear. (nvars=%d, ncons=%d)\n",nvars,ncons);
   }
   
   nErrorCode = LSgetObjective(pModel,&objval);
   APIERRORCHECK;

   nErrorCode = LSgetPrimalSolution(pModel,primal);
   APIERRORCHECK;

   if (stat==LS_STATUS_OPTIMAL || stat==LS_STATUS_BASIC_OPTIMAL ||
     stat==LS_STATUS_FEASIBLE || stat==LS_STATUS_LOCAL_OPTIMAL)
   {     
     printf("\n\nPrinting the solution ... \n\n");
     printf("obj = %20.15f \n",objval);
     for (i=0;i>> Step 7 <<< Delete the LINDO environment 
 */
 LSdeleteEnv(&pEnv);
}